﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Gemli.Data;
using Gemli.Data.Providers;
using System.Data;

namespace Tests.Gemli.Data
{
    [TestClass]
    public class DataModelQueryLinqTest
    {
        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext { get; set; }


        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test 
        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //
        #endregion

        private DataProviderBase _prevDefaultProvider;
        [TestInitialize()]
        public void Test_Initialize()
        {
            _prevDefaultProvider = ProviderDefaults.AppProvider;
            var mockRepos = new MemoryDataProvider();
            var mockTable = new DataTable("mock_table");
            mockTable.Columns.Add("mock_table_id", typeof(int));
            mockTable.Columns.Add("string_value", typeof(string));
            mockTable.BeginLoadData();
            mockTable.Rows.Add(1, "abc");
            mockTable.Rows.Add(2, "def");
            mockTable.Rows.Add(3, "ghi");
            mockTable.EndLoadData();
            mockRepos.AddTable(mockTable);
            ProviderDefaults.AppProvider = mockRepos;
        }

        [TestCleanup()]
        public void Test_Cleanup()
        {
            ProviderDefaults.AppProvider = _prevDefaultProvider;
        }


        [DataModelTable(Table = "mock_table")]
        public class MockObject
        {
            [DataModelColumn("mock_table_id")]
            public int ID { get; set; }

            [DataModelColumn("string_value")]
            public string MockStringValue { get; set; }
        }

        [TestMethod]
        public void CreateQueryTest()
        {
            var qp = ProviderDefaults.AppProvider as IQueryProvider;
            var q = qp.CreateQuery<DataModel<MockObject>>(null);
            Assert.IsNotNull(q);
        }

        [TestMethod]
        public void CreateQueryTest2()
        {
            try
            {
                var qp = ProviderDefaults.AppProvider as IQueryProvider;
                var q = qp.CreateQuery<MockObject>(null);
                Assert.IsNull(q); // MockObject is not a data model; fail
            }
            catch
            {
                Assert.IsTrue(true); // MockObject is not a data model; pass
            }
        }

        [TestMethod]
        public void SetQueryConditionTest()
        {
            var myCustomEntityQuery = new DataModelQuery<DataModel<MockObject>>();
            var linqq = myCustomEntityQuery.Where(mo => mo.Entity.MockStringValue == "dah");
            myCustomEntityQuery = linqq as DataModelQuery<DataModel<MockObject>>;
            Assert.AreEqual(myCustomEntityQuery.Conditions[0].CompareOp, Compare.Equal);
            Assert.AreEqual(myCustomEntityQuery.Conditions[0].CompareValue, "dah");
            Assert.AreEqual(myCustomEntityQuery.Conditions[0].FindMemberMappingBy, MemberMappingKeyType.ClrMember);
            Assert.AreEqual(myCustomEntityQuery.Conditions[0].EvalSubject, "MockStringValue");
        }

        [TestMethod]
        public void SetQueryConditionTest2()
        {
            var myCustomEntityQuery = new DataModelQuery<DataModel<MockObject>>();
            var linqq = myCustomEntityQuery.Where(mo => mo.Entity.MockStringValue != "dah");
            myCustomEntityQuery = linqq as DataModelQuery<DataModel<MockObject>>;
            Assert.AreEqual(myCustomEntityQuery.Conditions[0].CompareOp, Compare.NotEqual);
            Assert.AreEqual(myCustomEntityQuery.Conditions[0].CompareValue, "dah");
            Assert.AreEqual(myCustomEntityQuery.Conditions[0].FindMemberMappingBy, MemberMappingKeyType.ClrMember);
            Assert.AreEqual(myCustomEntityQuery.Conditions[0].EvalSubject, "MockStringValue");
        }

        [TestMethod]
        public void SetQueryConditionTest3()
        {
            var myCustomEntityQuery = new DataModelQuery<DataModel<MockObject>>();
            var linqq = myCustomEntityQuery.Where(mo=>((int)mo.GetPropertyValueByColumnName("customentity_id")) > -1);
            myCustomEntityQuery = linqq as DataModelQuery<DataModel<MockObject>>;
            Assert.AreEqual(myCustomEntityQuery.Conditions[0].CompareOp, Compare.GreaterThan);
            Assert.AreEqual(myCustomEntityQuery.Conditions[0].CompareValue, -1);
            Assert.AreEqual(myCustomEntityQuery.Conditions[0].FindMemberMappingBy, MemberMappingKeyType.DbColumn);
            Assert.AreEqual(myCustomEntityQuery.Conditions[0].EvalSubject, "customentity_id");
        }

        [TestMethod]
        public void SetQueryConditionTest4()
        {
            var myCustomEntityQuery = new DataModelQuery<DataModel<MockObject>>();

            var q = (from mo in myCustomEntityQuery
                     where mo.Entity.MockStringValue != "st00pid"
                     select mo) as DataModelQuery<DataModel<MockObject>>;

            Assert.AreEqual(Compare.NotEqual, q.Conditions[0].CompareOp);
            Assert.AreEqual("st00pid", q.Conditions[0].CompareValue);
            Assert.AreEqual(MemberMappingKeyType.ClrMember, q.Conditions[0].FindMemberMappingBy);
            Assert.AreEqual("MockStringValue", q.Conditions[0].EvalSubject);
        }

        [TestMethod]
        public void RunQueryTest1()
        {
            var myCustomEntityQuery = new DataModelQuery<DataModel<MockObject>>();

            var orderedlist = (from mo in myCustomEntityQuery
                               where mo.Entity.MockStringValue != "def"
                               orderby mo.Entity.MockStringValue
                               select mo).ToList();
            Assert.AreEqual(2, orderedlist.Count);
            Assert.AreEqual("abc", orderedlist[0].Entity.MockStringValue);
            Assert.AreEqual("ghi", orderedlist[1].Entity.MockStringValue);
        }

        [TestMethod]
        public void RunQueryTest2()
        {

            var myCustomEntityQuery = new DataModelQuery<DataModel<MockObject>>();

            var orderedlist = (from mo in myCustomEntityQuery
                               where mo.Entity.MockStringValue != "def" && mo.Entity.ID < 3
                               orderby mo.Entity.ID, mo.Entity.MockStringValue
                               select mo).ToList();
            Assert.AreEqual(1, orderedlist.Count);
            Assert.AreEqual("abc", orderedlist[0].Entity.MockStringValue);
        }
        
    }
}
